package com.lry.pda.bottom.mysql.frontend;


import com.lry.pda.bottom.mysql.backend.*;

import java.util.*;

public class LRValueParser {

    private Lexer lexer;
    private Stack<Integer> stack = new Stack<>();//存储节点编号的状态堆栈
    private Stack<Object> valueStack = new Stack<>();

    private Map<Integer, Map<Integer,Integer>> lrTable;
    private int inputToken;
    private String text;
    private QueryExpr queryExpr = new QueryExpr();
    private List<String> fields = new ArrayList<>();

    //select * from A where a=1 group by a order by a desc limit 0,1
    //select * from A where a=1 group by a limit 0,1
    //select * from A where a=1 order by a desc limit 0,1
    //select * from A where a=1  limit 0,1
    //select * from A  order by a desc limit 0,1
    //select * from A group by a

    public LRValueParser(Lexer lexer){
        this.lrTable = StateManager.getSelf().getLRTable();
        this.lexer = lexer;
    }

    private void init(){
        System.out.println("\nInput string for parsing:");
        this.lexer.clear();
        this.lexer.input();
        this.lexer.advance();
        this.inputToken = this.lexer.lookAhead;
        valueStack.clear();
        this.fields.clear();
        this.text = null;
        this.queryExpr = new QueryExpr();
        stack.clear();
        stack.push(0);//初始为0节点
    }

    private Integer getAction(Integer currentState, Integer currentInput) {
        Map<Integer, Integer> jump = lrTable.get(currentState);
        if (jump != null) {
            Integer next = jump.get(currentInput);
            if (next != null) {
                return next;
            }
        }
        return null;
    }

    public void parse(){
        init();
        Integer action = null;
        while(true){
            action = getAction(stack.peek(), inputToken);

            if (action == null) {
                //解析出错
                System.err.println("The input is denied");
                parse();
                return;
            }

            if(action==0){
                System.out.println("The input can be accepted");
                System.out.println(queryExpr);
                parse();
                return;
            }else
                if(action > 0){
                //shift 操作
                stack.push(action);//压入下一个节点编号
                if (MysqlTokenType.isTerminal(inputToken)) {
                    text = lexer.yytext;
                    valueStack.push(text);
                    lexer.advance();
                }
                inputToken = lexer.lookAhead;
            }else {
                int number = - action;
                State state = StateManager.getSelf().getState(stack.peek());
                Production product = state.getProduction(number);

                takeActionForReduce(product);

                inputToken = product.getLeft();
                int rightSize = product.getDotPos();
                while (rightSize > 0) {
                    stack.pop();
                    if(!valueStack.isEmpty()){
                        valueStack.pop();
                    }
                    rightSize--;
                }
                valueStack.push(queryExpr);
            }
        }
    }

    private void takeActionForReduce(Production product) {
        //1:query_expression -> query_expression_body opt_order_clause
        if(product.getNumber()==Grammar.QUERY_EXPR_BODY_TO_QUERY_EXPR){

        }
        //2:query_expression_body -> SELECT_SYM select_item_list from_clause opt_where_clause
        else if(product.getNumber()==Grammar.TO_QUERY_EXPR_BODY){

        }
        //3:select_item_list -> *
        else if(product.getNumber()==Grammar.TIMES_TO_SELECT_ITEM_LIST){

        }
        //4:select_item_list -> field_list
        else if(product.getNumber()==Grammar.FIELD_LIST_TO_SELECT_ITEM_LIST){
            this.queryExpr.getQueryExprBody().getFieldExpr().addFields(fields);
            fields.clear();
        }
        //5:field_list -> field field_list_term
        else if(product.getNumber()==Grammar.FIELD_TO_FIELD_LIST){
            String field = null;
            if(valueStack.peek() instanceof QueryExpr){
                field = (String) valueStack.get(valueStack.size()-2);
            }else{
                field = (String) valueStack.peek();
            }
            this.fields.add(field);
        }
        //6:field_list_term -> comma field_list | 空
        else if(product.getNumber()==Grammar.FIELD_LIST_TO_FIELD_LIST_TERM){

        }
        //7:from_clause -> FROM_SYM table
        else if(product.getNumber()==Grammar.FROM_SYM_TO_FROM_CLAUSE){
            this.queryExpr.getQueryExprBody().setTable(text);
        }
        //8: opt_where_clause -> opt_group_clause
        else if(product.getNumber()==Grammar.OPT_GROUP_CLAUSE_TO_OPT_WHERE_CLAUSE){

        }
        //9：opt_where_clause -> WHERE_SYM where_clause opt_group_clause
        else if(product.getNumber()==Grammar.WHERE_SYM_TO_OPT_WHERE_CLAUSE){
            WhereExpr whereExpr = new WhereExpr();

        }
        //10：where_clause -> field compare where_val where_clause_term
        else if(product.getNumber()==Grammar.FIELD_TO_WHERE_CLAUSE){
            WhereKV whereKV = this.queryExpr.getQueryExprBody().getWhereExpr().getKv();
            if(valueStack.peek() instanceof QueryExpr){
                whereKV.setValue((String) valueStack.get(valueStack.size()-2));
                whereKV.setField((String) valueStack.get(valueStack.size()-4));
            }else{

                whereKV.setValue((String) valueStack.peek());
                whereKV.setField((String) valueStack.get(valueStack.size()-3));
            }
        }
        //11：where_clause_term -> AND_SYM where_clause | 空
        else if(product.getNumber()==Grammar.AND_TO_WHERE_CLAUSE_TERM){
            WhereExpr whereExpr = new WhereExpr();
        }
        //12：compare -> eq
        else if(product.getNumber()==Grammar.EQ_TO_COMPARE){
            WhereKV whereKV = new WhereKV();
            whereKV.setMysqlTokenType(MysqlTokenType.EQ);
            this.queryExpr.getQueryExprBody().getWhereExpr().addKv(whereKV);
        }
        //13：compare -> ge
        else if(product.getNumber()==Grammar.GE_TO_COMPARE){
            WhereKV whereKV = new WhereKV();
            whereKV.setMysqlTokenType(MysqlTokenType.GE);
            this.queryExpr.getQueryExprBody().getWhereExpr().addKv(whereKV);
        }
        //14: compare -> gt
        else if(product.getNumber()==Grammar.GT_TO_COMPARE){
            WhereKV whereKV = new WhereKV();
            whereKV.setMysqlTokenType(MysqlTokenType.GT);
            this.queryExpr.getQueryExprBody().getWhereExpr().addKv(whereKV);
        }
        //15：compare -> le
        else if(product.getNumber()==Grammar.LE_TO_COMPARE){
            WhereKV whereKV = new WhereKV();
            whereKV.setMysqlTokenType(MysqlTokenType.LE);
            this.queryExpr.getQueryExprBody().getWhereExpr().addKv(whereKV);
        }
        //16：compare -> lt
        else if(product.getNumber()==Grammar.LT_TO_COMPARE){
            WhereKV whereKV = new WhereKV();
            whereKV.setMysqlTokenType(MysqlTokenType.LT);
            this.queryExpr.getQueryExprBody().getWhereExpr().addKv(whereKV);
        }
        //17：compare -> in
        else if(product.getNumber()==Grammar.IN_TO_COMPARE){
            WhereKV whereKV = new WhereKV();
            whereKV.setMysqlTokenType(MysqlTokenType.IN);
            this.queryExpr.getQueryExprBody().getWhereExpr().addKv(whereKV);
        }


        //18：opt_group_clause -> GROUP_BY_SYM field_list | 空
        else if(product.getNumber()==Grammar.GROUP_SYM_TO_OPT_GROUP_CLAUSE){
            this.queryExpr.getQueryExprBody().getGroupExpr().getFieldExpr().addFields(fields);
            fields.clear();
        }
        //19：opt_order_clause -> opt_limit_clause
        else if(product.getNumber()==Grammar.OPT_LIMIT_CLAUSE_TO_OPT_ORDER_CLAUSE){

        }
        //20：opt_order_clause -> ORDER_SYM BY_SYM order_item opt_limit_clause
        else if(product.getNumber()==Grammar.ORDER_SYM_TO_OPT_ORDER_CLAUSE){
            this.queryExpr.getOrderExpr().getFieldExpr().addFields(fields);
        }
        //21：order_item -> field_list order_asc_desc
        else if(product.getNumber()==Grammar.FIELD_LIST_TO_ORDER_ITEM){

        }
        //22：order_asc_desc -> ASC_SYM  | 空
        else if(product.getNumber()==Grammar.ASC_SYM_TO_ORDER_ASC_DESC){

        }
        //23：order_asc_desc -> DESC_SYM | 空
        else if(product.getNumber()==Grammar.DESC_SYM_TO_ORDER_ASC_DESC){
            this.queryExpr.getOrderExpr().setMysqlTokenType(MysqlTokenType.DESC_SYM);
        }
        //24：opt_limit_clause -> LIMIT_SYM num comma num  | 空
        else if(product.getNumber()==Grammar.LIMIT_SYM_TO_OPT_LIMIT_CLAUSE){
            this.queryExpr.getLimitExpr().setOffset(Integer.valueOf((String) valueStack.get(valueStack.size()-3)));
            this.queryExpr.getLimitExpr().setRows(Integer.valueOf((String) valueStack.peek()));
        }
    }

    public static void main(String[] args) {
        ProductionManager productionManager = ProductionManager.getSelf();
        productionManager.init();

        StateManager stateManager = StateManager.getSelf();
        stateManager.buildTransitionStateMachine();

        LRValueParser lrParser = new LRValueParser(new Lexer());
        lrParser.parse();
    }
}
